#ifndef _TWITTER_RESOURCE_USER_H_
#define _TWITTER_RESOURCE_USER_H_
#include "object.h"

NS_BEGIN(Twit)
NS_BEGIN(Resource)
NS_BEGIN(User)

template <typename T>
class TObjectUser:public Object<T>
{
public:
   TObjectUser(IOAuth& o, const char* file):Object<T>(o, "users",file){};
};

typedef TObjectUser<Value::User> OUserVUser;
typedef TObjectUser<Value::Users> OUserVUsers;
typedef TObjectUser<Value::Categories> OUserVCategories;

/**
* @brief 
*  Returns extended information of a given user, specified by ID or screen name as per the 
*  required id parameter. The author's most recent status will be returned inline.
*/
class Show:public OUserVUser
{
public:
	Show(IOAuth& o):OUserVUser(o,"show"){ setConstraints(false,true); }

   /**
   * @param screen_name The screen name of the user for whom to return results for. 
   *  Helpful for disambiguating when a valid screen name is also a user ID.
   */
   bool request(std::string screen_name)
   {
	   setParam("screen_name", screen_name.c_str());
	   return OUserVUser::request();
   }

   /**
   * @param user_id The ID of the user for whom to return results for. 
   *  Helpful for disambiguating when a valid user ID is also a valid screen name.
   */
   bool request(Value::UniqueID user_id)
   {
	   setParam("user_id", user_id.toString().c_str());
	   return OUserVUser::request();
   }

   /**
   * @param screen_name The screen name of the user for whom to return results for. 
   *  Helpful for disambiguating when a valid screen name is also a user ID.
   */
   Value::User& get(std::string screenName)
   {
		setParam("screen_name", screenName.c_str());
		return OUserVUser::get();
   }
   
   /**
   * @param user_id The ID of the user for whom to return results for. 
   *  Helpful for disambiguating when a valid user ID is also a valid screen name.
   */
   Value::User& get(Value::UniqueID userId)
   {
	   setParam("user_id", userId.toString().c_str());
	   return OUserVUser::get();
   }

   /**
   * @brief 
   *  When set to either true, t or 1, each tweet will include a node called "entities,". 
   *  This node offers a variety of metadata about the tweet in a discreet structure, 
   *  including: user_mentions, urls, and hashtags. While entities are opt-in on timelines at present, 
   *  they will be made a default component of output in the future. 
   *  See Tweet Entities for more detail on entities.
   */
   void setIncludeEntities(bool v)__IncludeEntitiesCode
};


/**
* @brief 
*  Return up to 100 users worth of extended information, specified by either ID, screen name, 
*  or combination of the two. The author's most recent status 
*  (if the authenticating user has permission) will be returned inline.
*/
class Lookup:public OUserVUsers
{
    __DoNotUse__ bool request(){ return OUserVUsers::request(); }

	inline std::string stringArray2string(std::vector<std::string>& arr)
	{
		std::string ret;
		const size_t nSize = arr.size();
		for(size_t idx=0; idx<nSize; idx++)
		{
			ret += arr[idx];
			if(nSize-1 == idx) break;
			ret += ",";
		}
		return ret;
	}

	inline std::string IDs2string(Value::IDs& ids)
	{
		std::string ret;
		const size_t size = ids.size();
		for(size_t idx=0; idx<size; idx++)
		{
			ret += ids[idx].toString();
			if(size-1 == idx) break;
			ret += ",";
		}
		return ret;
	}
public:
	Lookup(IOAuth& o):OUserVUsers(o,"lookup"){ setConstraints(true,true); }
   
   /**
   * @param user screen_name
   *  screen_name
   *  A comma separated list of screen names, up to 100 are allowed in a single request.
   *  ex.) http://api.twitter.com/1/users/Lookup.json?screen_name=twitterapi,twitter
   */
   bool request(std::string screen_name)
   {
	   setParam("screen_name", screen_name.c_str());
	   return OUserVUsers::request();
   }

   bool request(std::vector<std::string>& screenNames)
   {
	   std::string names = stringArray2string(screenNames);
	   setParam("screen_name", names.c_str());
	   return OUserVUsers::request();
   }

   /**
   * @param user_id
   *  user_id
   *  A comma separated list of user IDs, up to 100 are allowed in a single request.
   *  ex.)  http://api.twitter.com/1/users/Lookup.json?user_id=783214,6253282
   */
   bool request(Value::UniqueID userId)
   {
	   setParam("user_id", userId.toString().c_str());
	   return OUserVUsers::request();
   }
   bool request(Value::IDs& userIDs)
   {
	   std::string ids = IDs2string(userIDs);
	   setParam("user_id", ids.c_str());
	   return OUserVUsers::request();
   }

   /**
   * @param user screen_name
   *  screen_name
   *  A comma separated list of screen names, up to 100 are allowed in a single request.
   *  ex.) http://api.twitter.com/1/users/Lookup.json?screen_name=twitterapi,twitter
   */
   Value::Users& get(std::string screenName)
   {
		setParam("screen_name", screenName.c_str());
		return OUserVUsers::get();
   }
   Value::Users& get(std::vector<std::string>& screenNames)
   {
	   std::string names = stringArray2string(screenNames);
	   setParam("screen_name", names.c_str());
	   return OUserVUsers::get();		
   }

   /**
   * @param user_id
   *  user_id
   *  A comma separated list of user IDs, up to 100 are allowed in a single request.
   *  ex.)  http://api.twitter.com/1/users/Lookup.json?user_id=783214,6253282
   */
   Value::Users& get(Value::UniqueID userId)
   {
		setParam("user_id", userId.toString().c_str());
		return OUserVUsers::get();
   }

   Value::Users& get(Value::IDs& userIDs)
   {
	   std::string ids = IDs2string(userIDs);
	   setParam("user_id", ids.c_str());
	   return OUserVUsers::get();
   }

   void setIncludeEntities(bool v) __IncludeEntitiesCode
};


/**
* @brief 
*  Runs a search for users similar to Find People button on Twitter.com. 
*  The results returned by people search on Twitter.com are the same as 
*  those returned by this API request.
*  Only the first 1000 matches are available.
*/
class Search:public OUserVUsers
{
	__DoNotUse__ bool request(){ return OUserVUsers::request(); }
public:
	Search(IOAuth& o):OUserVUsers(o,"search"){ setConstraints(true,true); }
public:

   /**
   * @param q The Search query to run against people Search.
   *  ex.) http://api.twitter.com/1/users/Search.json?q=Twitter%20API
   */
   bool request(std::wstring q)
   {
	   setParam("q", Convert::UnicodeToUtf8(q).c_str());
	   return OUserVUsers::request();
   }

   /**
   * @param q The Search query to run against people Search.
   *  ex.) http://api.twitter.com/1/users/Search.json?q=Twitter%20API
   */
   Value::Users& get(std::wstring q)
   {
		setParam("q", Convert::UnicodeToUtf8(q).c_str());
		return OUserVUsers::get();
   }

   /**
   * @param v The number of people to retrieve. Maxiumum of 20 allowed per page.
   *  ex.) http://api.twitter.com/1/users/Search.json?per_page=5
   */
   void setPerPage(size_t v)
   {
	   setParam("per_page", (int)v);
   }

   /**
   * @param v Specifies the page of results to retrieve.
   *  ex.) http://api.twitter.com/1/users/Search.json?page=3
   */
   void setPage(size_t v)
   {
	   setParam("page", (int)v);
   }

   void setIncludeEntities(bool v) __IncludeEntitiesCode
};

/**
* @brief 
*  Access to Twitter's suggested user list. This returns the list of suggested user categories. 
*  The category can be used in the users/SuggestedCategories/category endpoint to get the users in that category.
*/
struct SuggestedCategories:public OUserVCategories
{
	SuggestedCategories(IOAuth& o):OUserVCategories(o,"suggestions"){ setConstraints(false,true); }
};

/**
* @brief 
*  Access the users in a given category of the Twitter suggested user list.
*  It is recommended that end clients cache this data for no more than one hour.
*/
class SuggestedUsers:public OUserVUsers
{

	__DoNotUse__ bool request(){ return OUserVUsers::request(); }
public:
	SuggestedUsers(IOAuth& o):OUserVUsers(o,"suggestions")
	{
		std::string path = getPath();
		path += "/";
		path += getFile();
		setPath(path.c_str());
		setConstraints(false,true);
	}

   /**
   * @param slug The short name of list or a category
   *  ex.) http://api.twitter.com/1/users/Suggestions/twitter.json
   */
   bool request(std::string categorySlug)
   {
	   setFile(categorySlug.c_str());
	   return OUserVUsers::request();
   }

   /**
   * @param slug The short name of list or a category
   *  ex.) http://api.twitter.com/1/users/Suggestions/twitter.json
   */
   Value::Users& get(std::string categorySlug)
   {
		setFile(categorySlug.c_str());
		return OUserVUsers::get();
   }
};


/**
* @brief 
*  Access the profile image in various sizes for the user with the indicated screen_name. 
*  If no size is provided the normal image is returned. 
*  This Resource does not return JSON or XML, but instead returns a 302 redirect 
*  to the actual image Resource.
*  This method should only be used by application developers to Lookup or check the profile image URL 
*  for a user. This method must not be used as the image source URL presented to users of 
*  your application.
*/
//struct _profile_image:public res_user
//{
//   _profile_image(IOAuth& o);
//private:
//   inline bool request(){ return res_user::request();  }
//public:
//
//   /**
//   * @param screen_name
//   *  The screen name of the user for whom to return results for. 
//   *  Helpful for disambiguating when a valid screen name is also a user ID.
//   *  ex.) http://api.twitter.com/1/users/profile_image/twitter.json
//   */
//   bool request(std::string screen_name);
//
//   /**
//   * @param size 
//   *  Specifies the size of image to fetch. Not specifying a size will give the default, 
//   *  normal size of 48px by 48px. 
//   *  Valid options include:
//   *     bigger - 73px by 73px
//   *     normal - 48px by 48px
//   *     mini - 24px by 24px
//   */
//   void set_size(std::string size);
//};

/**
* @brief 
*  Returns a user's friends, each with current status inline. 
*  They are ordered by the order in which the user followed them, 
*  most recently followed first, 100 at a time. (Please note that the response set isn't guaranteed 
*  to be 100 every time as suspended users will be filtered out.)
*  Use the cursor option to access older friends.
*  With no user specified, request defaults to the authenticated user's friends.
*  It is also possible to request another user's friends list via the id, 
*  screen_name or user_id parameter.
*/
class Friends:public OStatusesVUsers
{
public:
	Friends(IOAuth& o):OStatusesVUsers(o,"friends"){ setConstraints(false,true); }

   /**
   * @param v The ID of the user for whom to return results for. 
   *  Helpful for disambiguating when a valid user ID is also a valid screen name.
   */
   void setUserId(Value::UniqueID v)
   {
	   setParam("user_id", v.toString().c_str());
   }

   /**
   * @param The screen name of the user for whom to return results for. 
   *  Helpful for disambiguating when a valid screen name is also a user ID.
   */
   void setScreenName(std::string v)
   {
	   setParam("screen_name", v.c_str());
   }

   /**
   * @param v
   *  Breaks the results into pages. This is recommended for users who are following many users. 
   *  Provide a Value of -1 to begin paging. Provide values as returned in 
   *  the response body's next_cursor and previous_cursor attributes to page back and forth in the list.
   *  http://api.twitter.com/1/statuses/friends.json?cursor=12893764510938
   */
   void setCursor(double cursor){ setParam("cursor", Util::toString(cursor).c_str()); }

   void setIncludeEntities(bool v) __IncludeEntitiesCode
};


/**
* @brief 
*  Returns the authenticating user's followers, each with current status inline. 
*  They are ordered by the order in which they followed the user, 100 at a time. 
*  (Please note that the response set isn't guaranteed to be 100 every time as suspended users 
*  will be filtered out.)
*  Use the cursor parameter to access earlier followers.
*/
class Followers:public Friends
{
public:
	Followers(IOAuth& o):Friends(o){ setFile("followers");	}
};
NS_END;

DeclareResourceClass(CUser)
CUser(IOAuth& o):Show(o), Lookup(o), Search(o), SuggestedCategories(o), SuggestedUsers(o), Friends(o), Followers(o){}
public:
User::Show                 Show;
User::Lookup               Lookup;
User::Search               Search;
User::SuggestedCategories  SuggestedCategories;
User::SuggestedUsers       SuggestedUsers;
//User::_profile_image   profile_image;
__deprecated User::Friends              Friends;
__deprecated User::Followers            Followers;
EndResourceClass;
NS_END;
NS_END;

#endif /*_TWITTER_RESOURCE_USER_H_*/
